package com.nirvana.item;

import com.intellij.openapi.ui.Messages;
import com.nirvana.MainPanel;
import com.nirvana.config.PluginConfig;
import com.nirvana.data.DbFieldInfo;
import com.nirvana.data.DefPropertyData;
import com.nirvana.data.DependenceData;
import com.nirvana.data.DependenceMetaData;
import com.nirvana.factory.FileResolveFactory;
import com.nirvana.factory.ItemFactory;
import com.nirvana.generate.*;
import com.nirvana.resolve.AbstractResolver;
import com.nirvana.type.ItemType;
import com.nirvana.utils.CmdLineUtil;
import com.nirvana.utils.DbUtil;
import com.nirvana.utils.UIUtil;
import org.apache.commons.lang3.StringUtils;

import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.List;
import java.util.*;

public class CommonItem {
    public MainPanel mainPanel;
    public ItemType itemType;
    public JPanel parent;
    public JPanel panelTemplate;
    public JRadioButton radioButtonTemplate;
    public JTextField textFieldTemplate;
    public Color selectedBackgroudColor;
    public AbstractItem curSelectedItem;
    public final ArrayList<AbstractItem> itemList = new ArrayList<>();
    public final ButtonGroup buttonGroup = new ButtonGroup();
    // Def类名/初始化代码生成内容
    public JTextField textField;

    private AbstractResolver defResolver;

    public CommonItem(ItemType type, MainPanel mainPanel, JPanel container, JPanel panel, JRadioButton radioButton, JTextField textField1, JTextField textField2) {
        itemType = type;
        this.mainPanel = mainPanel;
        parent = container;
        panelTemplate = panel;
        radioButtonTemplate = radioButton;
        textFieldTemplate = textField1;
        textField = textField2;
        selectedBackgroudColor = panelTemplate.getBackground();
        panelTemplate.setVisible(false);
        parent.removeAll();
    }

    public void refresh() {
        itemList.forEach(item -> UIUtil.refresh(item.itemPanel));
    }

    public void delete() {
        if (curSelectedItem == null) return;
        parent.remove(curSelectedItem.itemPanel);
        itemList.remove(curSelectedItem);
        refresh();
        UIUtil.refresh(parent);
        curSelectedItem = null;
    }

    public void copy() {
        if (curSelectedItem == null) return;
        add(true);
    }

    public void add(boolean copy) {
        AbstractItem item = ItemFactory.createItem(itemType);
        int index = -1;
        if (copy) {
            item.copy(curSelectedItem);
            index = getCurSelectedItemIndex() + 1;
        }
        parent.add(item.itemPanel, index);
        UIUtil.refresh(parent);
        refresh();
    }

    public void clearAll() {
        curSelectedItem = null;
        itemList.clear();
        textField.setText("");
        parent.removeAll();
        UIUtil.refresh(parent);
    }

    public void populateData(List<DependenceData> datas) {
        if (itemType != ItemType.ResolvePropertyItem) return;

        parent.removeAll();
        datas.stream().sorted(new Comparator<>() {
            @Override
            public int compare(DependenceData o1, DependenceData o2) {
                return o1.getIndex() - o2.getIndex();
            }

            @Override
            public boolean equals(Object obj) {
                return false;
            }
        }).forEach(data -> {
            for (DependenceMetaData dependenceMetaData : data.getMetaDataList()) {
                ResolvePropertyItem item = (ResolvePropertyItem) ItemFactory.createItem(itemType);
                item.populate(data.getFullClassName(), dependenceMetaData);

                parent.add(item.itemPanel);
            }
        });
        refresh();
        UIUtil.refresh(parent);
    }


    private int getCurSelectedItemIndex() {
        Component[] components = parent.getComponents();
        for (int i = 0; i < components.length; i++) {
            if (components[i] == curSelectedItem.itemPanel) {
                return i;
            }
        }
        return -1;
    }

    public void moveUp() {
        if (curSelectedItem == null) return;
        int index = getCurSelectedItemIndex() - 1;
        if (index < 0) return;
        reposition(index);
    }

    private void reposition(int index) {
        parent.remove(curSelectedItem.itemPanel);
        parent.add(curSelectedItem.itemPanel, index);
        itemList.remove(curSelectedItem);
        itemList.add(index, curSelectedItem);
        UIUtil.refresh(parent);
    }

    public void moveDown() {
        if (curSelectedItem == null) return;
        int index = getCurSelectedItemIndex() + 1;
        if (index >= parent.getComponents().length) return;
        reposition(index);
    }

    public void resolve(File file) {
        itemList.forEach(item -> parent.remove(item.itemPanel));
        itemList.clear();

        defResolver = FileResolveFactory.getResolver(file);
        List<DefPropertyData> resolve = defResolver.resolve();
        resolve.forEach(data -> {
            DefPropertyItem item = (DefPropertyItem) ItemFactory.createItem(itemType);
            item.populate(data);
            parent.add(item.itemPanel);
        });
    }

    public void generateDefFile() {
        if (itemType != ItemType.DefPropertyItem) return;
        if (checkCondition()) return;
        if (!PluginConfig.getInstance().skipGenerateDef()) {
            XmlDefClassGenerator.getInstance().generate();
        }
        InitCodeGenerator.getInstance().generate();
        if (PluginConfig.getInstance().useFlatBuffers()) {
            FbsGenerator.getInstance().generate();
            BaseDefClassGenerator.getInstance().generate();
            DefXmlWrapperClassGenerator.getInstance().generate();
            DefFbWrapperClassGenerator.getInstance().generate();
        }
        PluginConfig.reloadAllFilesFromDisk();
        SwingUtilities.invokeLater(() -> Messages.showInfoMessage(textField.getText() + "生成成功", "生成结果"));
    }

    private boolean checkCondition() {
        if (itemList.isEmpty()) {
            Messages.showErrorDialog("请添加属性字段再生成代码", "Def生成错误");
            return true;
        }

        Set<String> propertyNameSet = new HashSet<>();
        for (AbstractItem item : itemList) {
            if (item instanceof DefPropertyItem defPropertyItem) {
                String propertyName = defPropertyItem.getPropertyName();
                if (StringUtils.isBlank(propertyName)) {
                    Messages.showErrorDialog("属性字段不能为空", "Def生成错误");
                    return true;
                }
                if (propertyNameSet.contains(propertyName)) {
                    Messages.showErrorDialog("属性字段不能为重复", "Def生成错误");
                    return true;
                }
                if (defPropertyItem.isResolve() && StringUtils.isBlank(defPropertyItem.getOriginPropertyName())) {
                    int index = PluginConfig.getInstance().getDependenceDataByType(defPropertyItem.getPropertyType()).paramTypeIndex(defPropertyItem.getResolveMethodName());
                    if (index == 0) {
                        Messages.showErrorDialog("非auto且入参为String解析方式请定义源字段", "Def生成错误");
                        return true;
                    }
                }
                propertyNameSet.add(propertyName);
            }
        }
        if (PluginConfig.getInstance().useFlatBuffers()) {
            int exitCode = CmdLineUtil.exec("%s\\flatc.exe --version".formatted(
                    PluginConfig.getInstance().flatBuffersInstallPath()
            ));
            if (exitCode != 0) {
                Messages.showErrorDialog("flatc.exe不可用，请检查flatc.exe安装路径" + PluginConfig.getInstance().flatBuffersInstallPath(), "flatc错误");
                return true;
            }
        }
        return false;
    }

    public String getDefClassName() {
        if (defResolver == null) return "";
        return defResolver.getDefClassName();
    }

    public void saveResolve() {
        PluginConfig.getInstance().clearCache();
        int index = 0;
        for (AbstractItem item : itemList) {
            if (item instanceof ResolvePropertyItem resolvePropertyItem) {
                if (StringUtils.isBlank(resolvePropertyItem.getPropertyName()) || StringUtils.isBlank(resolvePropertyItem.getResolveMethod())) {
                    parent.remove(item.itemPanel);
                    continue;
                }
                index = PluginConfig.getInstance().addNewDependence(resolvePropertyItem, index);
            }
        }
        PluginConfig.getInstance().saveConfig();
        ItemFactory.getCommonItem(ItemType.DefPropertyItem).refreshAllDefPropertyItemComBox();
    }

    public void refreshAllDefPropertyItemComBox() {
        for (AbstractItem item : itemList) {
            if (item instanceof DefPropertyItem defPropertyItem) {
                defPropertyItem.refreshComboBox();
            }
            UIUtil.refresh(item.itemPanel);
        }
        UIUtil.refresh(parent);
    }

    public void tableChange(String tableName) {
        if (itemType != ItemType.TableFieldItem) return;
        itemList.clear();
        parent.removeAll();
        Collection<DbFieldInfo> tableFieldList = DbUtil.getTableFieldList(tableName);
        for (DbFieldInfo dbFieldInfo : tableFieldList) {
            TableFieldItem item = (TableFieldItem) ItemFactory.createItem(itemType);
            item.populate(dbFieldInfo);
            parent.add(item.itemPanel);
        }
        UIUtil.refresh(parent);
        refresh();
    }
}
